﻿#region File Description
/****************************************************************************
*                                                                           *
* Texture.                                                                  *
*                                                                           *
* Copyright (c) Ionescu Marius. All rights reserved(2010).                  *
*                                                                           *
****************************************************************************/
#endregion

#region Using directives
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.IO;
//using RacingGame;
//using RacingGame.GameLogic;
//using RacingGame.Helpers;
#endregion

namespace XNA_FRAMEWORK
{
	public class Texture : IDisposable
	{
		#region Variables
		public static SpriteBatch alphaSprite;
		public static SpriteBatch additiveSprite;

		protected string texFilename = "";

		public string Filename
		{
			get
			{
				return texFilename;
			}
		}

		protected int texWidth, texHeight;

		public int Width
		{
			get
			{
				return texWidth;
			}
		}

		public int Height
		{
			get
			{
				return texHeight;
			}
		}

		public Rectangle GfxRectangle
		{
			get
			{
				return new Rectangle(0, 0, texWidth, texHeight);
			}
		}

		private Vector2 precaledHalfPixelSize = Vector2.Zero;

		public Vector2 HalfPixelSize
		{
			get
			{
				return precaledHalfPixelSize;
			}
		}

		protected void CalcHalfPixelSize()
		{
			precaledHalfPixelSize = new Vector2(
				(1.0f / (float)texWidth) / 2.0f,
				(1.0f / (float)texHeight) / 2.0f);
		}

		protected Texture2D internalXnaTexture;

		public virtual Texture2D XnaTexture
		{
			get
			{
				return internalXnaTexture;
			}
		}

		protected bool loaded = true;
		protected string error = "";

		public virtual bool Valid
		{
			get
			{
				return loaded &&
					internalXnaTexture != null;
			}
		}

		protected bool hasAlpha = false;
		public bool HasAlphaPixels
		{
			get
			{
				return hasAlpha;
			}
		}
		#endregion

		#region Constructor
		public Texture(string setFilename)
		{
			if (alphaSprite == null)
				alphaSprite = new SpriteBatch(xnaGameMgr.Device);

			if (additiveSprite == null)
				additiveSprite = new SpriteBatch(xnaGameMgr.Device);

			if (String.IsNullOrEmpty(setFilename))
				throw new ArgumentNullException("setFilename",
					"Unable to create texture without valid filename.");

			texFilename = Path.GetFileNameWithoutExtension(setFilename);
			string fullFilename = null;//Path.Combine(Directories.ContentDirectory + "\\textures", texFilename);

			internalXnaTexture = xnaGameMgr.ContentXNA.Load<Texture2D>(fullFilename);

			texWidth = internalXnaTexture.Width;
			texHeight = internalXnaTexture.Height;

			hasAlpha = (internalXnaTexture.Format == SurfaceFormat.Dxt5 ||
						internalXnaTexture.Format == SurfaceFormat.Dxt3);

			loaded = true;

			CalcHalfPixelSize();
		}

		protected Texture()
		{
		}

		public Texture(Texture2D tex)
		{
			if (alphaSprite == null)
				alphaSprite = new SpriteBatch(xnaGameMgr.Device);

			if (additiveSprite == null)
				additiveSprite = new SpriteBatch(xnaGameMgr.Device);

			if (tex == null)
				throw new ArgumentNullException("tex");

			internalXnaTexture = tex;

			texWidth = internalXnaTexture.Width;
			texHeight = internalXnaTexture.Height;

			loaded = true;

			hasAlpha = (internalXnaTexture.Format == SurfaceFormat.Dxt5 ||
						internalXnaTexture.Format == SurfaceFormat.Dxt3);

			CalcHalfPixelSize();
		}
		#endregion

		#region Disposing
		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (disposing)
			{
				if (internalXnaTexture != null)
					internalXnaTexture.Dispose();
				internalXnaTexture = null;
			}

			loaded = false;
		}
		#endregion

		#region Render on screen
		public void RenderOnScreen(Rectangle rect, Rectangle pixelRect)
		{
			alphaSprite.Draw(internalXnaTexture, rect, pixelRect, Color.White);
		}

		public void RenderOnScreen(Rectangle rect,
			int pixelX, int pixelY, int pixelWidth, int pixelHeight)
		{
			alphaSprite.Draw(internalXnaTexture, rect, new Rectangle(pixelX, pixelY,
				pixelWidth, pixelHeight), Color.White);
		}

		public void RenderOnScreen(Point pos)
		{
			alphaSprite.Draw(internalXnaTexture,
				new Rectangle(pos.X, pos.Y, texWidth, texHeight),
				new Rectangle(0, 0, texWidth, texHeight), Color.White);
		}

		public void RenderOnScreen(Rectangle renderRect)
		{
			alphaSprite.Draw(internalXnaTexture, renderRect, GfxRectangle, Color.White);
		}

		public void RenderOnScreenRelative16To9(int relX, int relY,
			Rectangle pixelRect)
		{
			alphaSprite.Draw(internalXnaTexture, xnaGameMgr.CalcRectangle(
				relX, relY, pixelRect.Width, pixelRect.Height),
				pixelRect, Color.White);
		}

		public void RenderOnScreenRelative4To3(int relX, int relY,
			Rectangle pixelRect)
		{
			alphaSprite.Draw(internalXnaTexture, xnaGameMgr.CalcRectangleKeep4To3(
				relX, relY, pixelRect.Width, pixelRect.Height),
				pixelRect, Color.White);
		}

		public void RenderOnScreenRelative1600(
			int relX, int relY, Rectangle pixelRect)
		{
			alphaSprite.Draw(internalXnaTexture, xnaGameMgr.CalcRectangle1600(
				relX, relY, pixelRect.Width, pixelRect.Height),
				pixelRect, Color.White);
		}

		public void RenderOnScreen(Rectangle rect, Rectangle pixelRect,
			Color color)
		{
			alphaSprite.Draw(internalXnaTexture, rect, pixelRect, color);
		}

		public void RenderOnScreen(Rectangle rect, Rectangle pixelRect,
			Color color, SpriteBlendMode blendMode)
		{
			if (blendMode == SpriteBlendMode.Additive)
				additiveSprite.Draw(internalXnaTexture, rect, pixelRect, color);
			else
				alphaSprite.Draw(internalXnaTexture, rect, pixelRect, color);
		}
		#endregion

		#region Rendering on screen with rotation
		public void RenderOnScreenWithRotation(
			Rectangle rect, Rectangle pixelRect,
			float rotation, Vector2 rotationPoint)
		{
			alphaSprite.Draw(internalXnaTexture, rect, pixelRect, Color.White, rotation,
				rotationPoint, SpriteEffects.None, 0);
		}
		#endregion

		#region To string
		public override string ToString()
		{
			return "Texture(filename=" + texFilename +
				", width=" + texWidth +
				", height=" + texHeight +
				", xnaTexture=" + (internalXnaTexture != null ? "valid" : "null") + ")";
		}
		#endregion
	}
}
